﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MakeTableTool
{
    public class MD5Checker
    {
        Dictionary<string, MD5Info> md5fileInfosDic = new Dictionary<string, MD5Info>();

        /// <summary>
        /// 加载MD5 Json 文件
        /// </summary>
        /// <param name="jsonPath"></param>
        public void LoadMD5Info(string jsonPath)
        {
            md5fileInfosDic.Clear();
            try
            {
                if(File.Exists(jsonPath))
                {
                    var jsonString = File.ReadAllText(jsonPath);
                    var md5fileInfos = JsonConvert.DeserializeObject<MD5FileInfos>(jsonString);
                    foreach(var file in md5fileInfos.files)
                    {
                        md5fileInfosDic.Add(file.fileName, file);
                    }
                }
            }
            catch(Exception e)
            {
                throw new Exception(string.Format("读取Md5 文件出错 ,{0} ,Message {1}" ,jsonPath,e.Message));
            }
        }

        /// <summary>
        /// 更新MD5 Json文件
        /// </summary>
        /// <param name="filePaths"></param>
        /// <param name="jsonPath"></param>
        public void UpdateNewMD5Json(List<FileInfo> filePaths,string jsonPath)
        {
            MD5FileInfos md5fileInfos = new MD5FileInfos();
            foreach (var filePath in filePaths)
            {
                var md5File = new MD5Info() { fileName = filePath.FullName, md5String = GetMD5HashFromFile(filePath.FullName) };
                md5fileInfos.files.Add(md5File);
            }

            var jsonString = JsonConvert.SerializeObject(md5fileInfos);
            File.WriteAllText(jsonString,jsonPath);
        }

        /// <summary>
        /// 获取经过更改的文件
        /// </summary>
        /// <param name="filePaths"></param>
        /// <returns></returns>
        public List<FileInfo> GetDirtyFiles(List<FileInfo> fileInfos)
        {
            List<FileInfo> result = new List<FileInfo>();
            foreach(var fileInfo in fileInfos)
            {
                var filePath = fileInfo.FullName;
                var md5 = GetMD5HashFromFile(filePath);

                if(md5fileInfosDic.ContainsKey(filePath))
                {
                    var oldMd5 = md5fileInfosDic[filePath];
                    if(!oldMd5.md5String.Equals(md5)) //文件有更新
                    {
                        result.Add(fileInfo);
                    }
                }
                else
                {
                    result.Add(fileInfo);
                }
            }

            return result;
        }
        /// <summary>
        /// 
        /// 获取文件MD5值
        /// </summary>
        /// <param name="fileName">文件绝对路径</param>
        /// <returns>MD5值</returns>
        public static string GetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("文件 "+ fileName+" ,GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }
    }

    public class MD5FileInfos
    {
        public List<MD5Info> files = new List<MD5Info>();
    }
    public class MD5Info
    {
        public string fileName;
        public string md5String;
    }
}
